#include "JCCParserTool.h"

#include <fstream>
#include <iostream>

#define HOW_MUCH_AHEAD_STRS 3

using namespace JCC::TOOL;

static std::string _unsigned = "unsigned";

static std::string _jccstr = "CJCCBridgeStr";

static std::string _basetype[] = {
	"char",
	"char*",
	"int",
	"int*",
	"long",
	"long*",
	"long long",
	"string"
	""
};


CJCCParserTool::CJCCParserTool(void)
{
	_class_info = new CClassInfo;
}

CJCCParserTool::~CJCCParserTool(void)
{
	delete _class_info;
}

bool JCC::TOOL::CJCCParserTool::StartParser( std::string& file_name_ )
{
	std::ifstream _infile(file_name_.c_str());

	if(_infile.bad())
	{
		std::cout<<"File is bad!"<<std::endl;

		_infile.close();

		return false;
	}

	bool _isfindstart = false;
	std::string _line_txt;

	while(getline(_infile, _line_txt))
	{
		if(!_isfindstart)
		{
			if(_line_txt.find("JCC_START", 0) != std::string::npos)
			{
				_isfindstart = true;
			}

			std::string().swap(_line_txt);

			continue;
		}

		if(_isfindstart)
		{
			if(_line_txt.find("JCC_END", 0) != std::string::npos)
			{
				_isfindstart = false;

				std::string().swap(_line_txt);

				continue;
			}
		}

		TrimMoreSpace(_line_txt);

		CombineType(_line_txt);

		if(_line_txt.length() > 0)
		{
			if(_line_txt[0] == '/')
			{
				std::string().swap(_line_txt);

				continue;
			}

			int _gaincounts = 0;
			std::string _aheadstrs[HOW_MUCH_AHEAD_STRS] = {""};

			while(_gaincounts < HOW_MUCH_AHEAD_STRS)
			{
				_aheadstrs[_gaincounts] = GainFirstStrBySpace(_line_txt);

				_gaincounts++;
			}

			if(!CheckAndSaveStrs(_aheadstrs))
			{
				_infile.close();

				return false;
			}
		}

		std::string().swap(_line_txt);
	}

	_infile.close();

	return true;
}

void JCC::TOOL::CJCCParserTool::TrimMoreSpace( std::string& src_str_)
{
	char c[2] = {0};
	bool _ishead = true;
	bool _ishavespace = false;
	std::string _ret;

	for(int i=0; i<src_str_.length(); i++)
	{
		if(_ishead)
		{
			if(src_str_[i] == ' ' || src_str_[i] == '\t')
			{
				continue;
			}
			else
			{
				_ishead = false;
			}
		}

		if(src_str_[i] == ' ' || src_str_[i] == '\t')
		{
			if(_ishavespace)
			{
				continue;
			}
			else
			{
				_ishavespace = true;;
			}
		}
		else
		{
			_ishavespace = false;
		}

		if(src_str_[i] == '\t')
		{
			c[0] = ' ';

			_ret.append(c);
		}
		else
		{
			c[0] = src_str_[i];

			_ret.append(c);
		}
	}

	src_str_ = _ret;
}

std::string JCC::TOOL::CJCCParserTool::GainFirstStrBySpace( std::string& src_str_ )
{
	std::string _ret;

	std::string::size_type _findpos = src_str_.find(" ", 0);

	if(_findpos != std::string::npos)
	{
		_ret = src_str_.substr(0, _findpos++);

		src_str_ = src_str_.substr(_findpos, -1);
	}
	else
	{
		_ret = src_str_;

		src_str_ = "";
	}

	return _ret;
}

void JCC::TOOL::CJCCParserTool::CombineType( std::string& src_str_ )
{
	char c[2] = {0};
	std::string _ret;

	for(int i=0; i<src_str_.length(); i++)
	{
		if(i + 1 < src_str_.length())
		{
			if((src_str_[i] == ' ' && src_str_[i + 1] == '*')
				||(src_str_[i] == ' ' && src_str_[i + 1] == ';'
				||(src_str_[i] == ' ' && src_str_[i + 1] == '<')
				||(src_str_[i] == ' ' && src_str_[i + 1] == '>')))
			{
				continue;
			}
		}
		
		if(i + 2 < src_str_.length() 
			&& (src_str_[i] == ' ' && src_str_[i + 1] == ':' && src_str_[i + 2] == ':'))
		{
			continue;
		}

		if(i - 2 >= 0 
			&& (src_str_[i] == ' ' && src_str_[i - 1] == ':' && src_str_[i - 2] == ':'))
		{
			continue;
		}

		if(i - 1 >= 0 && (src_str_[i] == ' ' && src_str_[i - 1] == '<'))
		{
			continue;
		}

		c[0] = src_str_[i];

		_ret.append(c);
	}

	src_str_ = _ret;
}

bool JCC::TOOL::CJCCParserTool::CheckAndSaveStrs( std::string* aheadstrs_ )
{
	std::string _type;
	std::string _name;
	CClassMemberInfo _info;

	if(aheadstrs_[0] == _unsigned)
	{
		_type = aheadstrs_[0] + aheadstrs_[1];

		_name = aheadstrs_[2].substr(0, aheadstrs_[2].length() - 1);
	}
	else if(aheadstrs_[0].find(_jccstr.c_str(), 0) != std::string::npos)
	{
		_type = _jccstr;

		_name = aheadstrs_[1].substr(0, aheadstrs_[1].length() - 1);
	}
	else if(aheadstrs_[0] == "long" && aheadstrs_[1] == "long")
	{
		_type = "long long";

		_name = aheadstrs_[2].substr(0, aheadstrs_[2].length() - 1);
	}
	else if(aheadstrs_[0].find("string", 0) != std::string::npos)
	{
		_type = "string";

		_name = aheadstrs_[1].substr(0, aheadstrs_[1].length() - 1);
	}
	else
	{
		_type = aheadstrs_[0];

		_name = aheadstrs_[1].substr(0, aheadstrs_[1].length() - 1);
	}

	if(_type.length() && _name.length())
	{
		_info.Type(_type);
		_info.Name(_name);

		_class_info->MembersInfo()->push_back(_info);
	}

	return true;
}

JCC::TOOL::CJCCParserTool::CJCCParserTool( const CJCCParserTool& val )
{
	_class_info = new CClassInfo;

	*this = val;
}

CJCCParserTool& JCC::TOOL::CJCCParserTool::operator=( const CJCCParserTool& val )
{
	_file_name = val._file_name;
	*_class_info = *(val._class_info);

	return *this;
}